﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace ChessEst1
{
    /// <summary>
    /// // class ChessDestiny is the driver program and accepts classes ChessPlayer and WinningChessPlayer
    /// // Instantiation of ChessDestiny occurs in Program.cs
    /// // important methods in ChessDestiny include ChessCombatFunc(); ChessPlayersCombat(int);  RecordWinnerFunc(int);
    /// // examining the code therein is self explanitory for the most part.
    /// //
    /// // various variables are used to track the winning statistics
    /// // certain lists are used to record the particular way certain winning players won, for example, 
    /// // 'WinningChessPlayerExtraordinaryUpsetsLst' is the list that tracks all winning chess players who had an Elo that was less than 2 sigma below the mean, 
    /// // indicating these weak players scored a big upset in winning the tournament
    /// </summary>


    class ChessDestiny
    {
        public ChessDestiny() { } //not used but useful as a placeholder

        public ChessDestiny(Dictionary<int, ChessPlayer> myChessPlayersDict, int PlayerEloInt, bool IsVerboseMode,
            int numberGamesPlayed, int numberIterations, double StandardDevAll, double MeanAllPlayers)
        {
            isVerbose = IsVerboseMode;
            this.numberGamesPlayed = numberGamesPlayed;
            this.numberIterations = numberIterations;
            this.subjectPlayerNumTotalWinsInt = 0; //initially no wins
            rand = new Random(); //time dependent seed //
            ChessPlayersDict = myChessPlayersDict;
            foreach (ChessPlayer cp in ChessPlayersDict.Values)
            {
                chessPlayersCurrentList.Add(cp);
            }

            //find the the subjectPlayerId by traversing the dictionary

            foreach (KeyValuePair<int, ChessPlayer> KV in ChessPlayersDict)
            {
                if (KV.Value.Rating == PlayerEloInt)
                {
                    subjectPlayerIdfound = KV.Value.PlayerID; //assign the (last) value found to the subjectPlayer
                }
            }

            this.StdDeviationAllPlayers = Math.Abs(StandardDevAll);
            this.MeanAllPlayers = Math.Abs(MeanAllPlayers);
            this.numberOfChessPlayers = ChessPlayersDict.Count();
            this.initializationFunction1(); //have at end of constructor
                 

        }
        /// <summary>
        /// // below used to initialize the logs;  
        /// </summary>

        int subjectPlayerEloLowerBound;//the subject player Elo plus a constant, PlusMinusEloInt, used for log
        int subjectPlayerEloUpperBound;//the subject player Elo plus a constant, PlusMinusEloInt, used for log  

        int twoSigmaAboveMeanElo;  //used in logging statistics
        int within1SigmaUpperElo;
        int within1SigmaLowerElo;
        int twoSigmaLessThanMeanElo; 


        private void initializationFunction1()
        {
            if (MeanAllPlayers == 0 || numberOfChessPlayers == 0) return;

            try
            {
                ChessPlayer cp_temp = ChessPlayersDict[subjectPlayerIdfound]; //fastest way of accessing a dictionary if key is certain to be found
                subjectPlayerEloLowerBound = cp_temp.Rating - PlusMinusEloInt;
                subjectPlayerEloUpperBound = cp_temp.Rating + PlusMinusEloInt;
            }
            catch (KeyNotFoundException ex)
            {
                Console.WriteLine(ex.Message);
            }
            catch (Exception ex1)
            {
                Console.WriteLine(ex1.Message);
            }

            twoSigmaAboveMeanElo = (int)(Math.Round(MeanAllPlayers)) + (2 * (int)(Math.Round(StdDeviationAllPlayers)));
            within1SigmaUpperElo = (int)(Math.Round(MeanAllPlayers)) + (1 * (int)(Math.Round(StdDeviationAllPlayers)));
            within1SigmaLowerElo = (int)(Math.Round(MeanAllPlayers)) - (1 * (int)(Math.Round(StdDeviationAllPlayers)));
            twoSigmaLessThanMeanElo = (int)(Math.Round(MeanAllPlayers)) - (2*(int)(Math.Round(StdDeviationAllPlayers)));
    
        }

        int numberOfChessPlayers = 0;

        Random rand;// = new Random(); //time dependent seed //place here to avoid non-random initialization error as is common
        private int numberGamesPlayed, numberIterations;

        double StdDeviationAllPlayers;
        double MeanAllPlayers;

        bool isVerbose = false; //set "test" or "verbose" mode where more information logged

        private int subjectPlayerIdfound = -1; //this is the subjectPlayerId //the key for the subjectPlayer in question from the dictionary

        private double subjectPlayerPercentWin;
        public double SubjectPlayerPercentWin
        {
            get
            {
                return subjectPlayerPercentWin;
            }

            set
            {
                subjectPlayerPercentWin = value;
            }
        }

        //
        private int subjectPlayerNumTotalWinsInt; //the total wins of the subject player

        private int PlusMinusEloInt = 50; //band about which log statistics are collected for winnerPlayer that is not subjectPlayer
        int winnerPlayerNumberTotalWinsPlusMinusEloInt; 

        private double winnerPlayerPercentWin;
        public double WinnerPlayerPercentWin
        {
            get
            {
                return winnerPlayerPercentWin;
            }

            set
            {
                winnerPlayerPercentWin = value;
            }
        }
        //
        // 
        // five phases of scalar distribution:  two std. dev from mean greater/lesser, 1-2 sigma from mean, and +-1 sigma from mean
        // 

        //III:
        private int winnerPlayerTwoSigmaGreaterint;

        //IIB:
        private int winnerPlayerBetweenOneAndTwoSigmaGreaterInt;  

        //II:
        private int winnerPlayerWithinOneSigmaint;

        //I.B.
        private int winnerPlayerBetweenOneAndTwoSigmaLESSERInt;

        //I:
        private int winnerPlayerTwoSigmaLessint;
        
        //
        List<WinningChessPlayer> WinningChessPlayerLst = new List<WinningChessPlayer>();
        List<WinningChessPlayer> WinningChessPlayerExtraordinaryUpsetsLst = new List<WinningChessPlayer>(); //to record extraordinary upsets

        public void WinningChessPlayerListPrintout()
        {
            if (WinningChessPlayerLst == null) return; //no need since instantiated, but since this function not in a loop, no big time penalty to leave this condition in
            if (WinningChessPlayerExtraordinaryUpsetsLst == null) //" "
            {
                return; 
            }
            else
            {
                if (WinningChessPlayerExtraordinaryUpsetsLst.Count > 0)
                {
                    string notice0aStr = "    "; //blank line
                    COutputStrings.Add(notice0aStr);
                    string noticeStr_ = "The list of top ten upsets (Elo less than 2 sigma below mean) for 10 or more players";
                    COutputStrings.Add(noticeStr_);
                    var result0 = WinningChessPlayerExtraordinaryUpsetsLst.Select(r => r).OrderBy(r => r.RoundN);
                    WinningChessPlayerExtraordinaryUpsetsLst = result0.ToList();

                    foreach (WinningChessPlayer wcp in WinningChessPlayerExtraordinaryUpsetsLst)
                    {
                        string s01WCPeU_ = String.Format("Upset Winning Player Stats (ID:{0}, Rating:{1}, Round:{2}, Total Score:{3},Avg. Elo Opponent:{4:0.0},Performance Elo:{5:0.0})", wcp.PlayerID, wcp.Rating, wcp.RoundN, wcp.TotalScore, wcp.OppositionRatingAvg, wcp.PerformanceRatingElo);
                        COutputStrings.Add(s01WCPeU_);

                        //////////// show the upsets blow by blow to the user

                            string s20234_ = String.Format("The upset player has the following stats for the round {0}:",wcp.RoundN); //  
                            COutputStrings.Add(s20234_);


                            Stack<int> myStackID_ = new Stack<int>();

                            foreach (int eye1 in wcp.PlayerOpponentIDList)
                            {
                                myStackID_.Push(eye1); //use stack so you can get the Player opponent and the Won/Loss side by side 

                            }

                            Stack<int> myStackWonLoss_ = new Stack<int>();  //use stack so you can get the Player opponent and the Won/Loss side by side
                            foreach (int eye2 in wcp.WonLossList)
                            {
                                myStackWonLoss_.Push(eye2);
                            }

                            int Lengthl1 = wcp.PlayerOpponentIDList.Count;
                            int Lenghtl2 = wcp.WonLossList.Count;

                            if (Lenghtl2 == Lengthl1) //quick sanity check    
                            {
                                for (int i = 0; i < Lenghtl2; i++)
                                {
                                    int eye1_OpponentID = myStackID_.Pop();

                                    double rating01temp_ = 0.0;

                                    try //add to dictionary ...
                                    {
                                        ChessPlayer cp_temp = ChessPlayersDict[eye1_OpponentID]; //fastest way to access dictionary if key is correct

                                        rating01temp_ = cp_temp.Rating;

                                    }
                                    catch (KeyNotFoundException ex)
                                    {
                                        Console.WriteLine(ex.Message);
                                    }
                                    catch (Exception ex1)
                                    {
                                        Console.WriteLine(ex1.Message);
                                    }

                                    //
                                    int eye2_WonLoss = myStackWonLoss_.Pop();
                                    string WonLossString_ = String.Empty;
                                    if (eye2_WonLoss == 0)
                                    {
                                        WonLossString_ = "L";
                                    }
                                    if (eye2_WonLoss == 1)
                                    {
                                        WonLossString_ = "W";
                                    }
                                    
                                    string s20343_ = String.Format("OpponentID, Rating, W/L result (W=Win; L=Loss): {0},{1:0.0},{2} ", eye1_OpponentID, rating01temp_, WonLossString_);
                                    COutputStrings.Add(s20343_);
                                }
                            }

                            string s3_3qaw_ = "...end upset player data...";
                            COutputStrings.Add(s3_3qaw_);

                    }

                    string noticeStr2_ = "End of upsets list";
                    COutputStrings.Add(noticeStr2_);
                }
            }
            
            ////sort WinningChessPlayerLst
            
            IEnumerable<WinningChessPlayer> result = new List<WinningChessPlayer>();
            
            //// use the following sort, better for final display to end user to sort by simply round number
            result = WinningChessPlayerLst.Select(t => t).OrderBy(t => t.RoundN);
            WinningChessPlayerLst = result.ToList();

            string S02_first1000wd_ = "First 1000 winners displayed (max.)";
            COutputStrings.Add(S02_first1000wd_);

            foreach (WinningChessPlayer wcp in WinningChessPlayerLst)
            {
                string statusStr_ = String.Empty;
                string s01_ = String.Format("Winning Player Stats (ID:{0}, Rating:{1}, Round:{2}, Total Score:{3}, Avg. Elo Opponent:{4:0.0},Performance Elo:{5:0.0})", wcp.PlayerID, wcp.Rating, wcp.RoundN, wcp.TotalScore, wcp.OppositionRatingAvg, wcp.PerformanceRatingElo);  //
                COutputStrings.Add(s01_);
                if (wcp.PlayerID == subjectPlayerIdfound)
                {
                    string s20234_ = String.Format("The winning player was also the chosen player and has the following stats for the round {0}",wcp.RoundN); //  
                    COutputStrings.Add(s20234_);
                   

                    Stack<int> myStackID_ = new Stack<int>();
                  
                    foreach (int eye1 in wcp.PlayerOpponentIDList)
                    {
                        myStackID_.Push(eye1); //use stack so you can get the Player opponent and the Won/Loss side by side 

                    }

                    Stack<int> myStackWonLoss_ = new Stack<int>();  //use stack so you can get the Player opponent and the Won/Loss side by side
                    foreach (int eye2 in wcp.WonLossList)
                    {
                        myStackWonLoss_.Push(eye2);
                    }

                    int Lengthl1 = wcp.PlayerOpponentIDList.Count;
                    int Lenghtl2 = wcp.WonLossList.Count;

                    if (Lenghtl2 == Lengthl1) //quick sanity check    
                    {
                        for (int i = 0; i < Lenghtl2; i++)
                        {
                            int eye1_OpponentID = myStackID_.Pop();
                             
                            double rating01temp_ = 0.0;

                            try //add to dictionary ...
                            {
                                ChessPlayer cp_temp = ChessPlayersDict[eye1_OpponentID]; //fastest way to access dictionary if key is correct
                               
                                rating01temp_ = cp_temp.Rating;

                            }
                            catch (KeyNotFoundException ex)
                            {
                                Console.WriteLine(ex.Message);
                            }
                            catch (Exception ex1)
                            {
                                Console.WriteLine(ex1.Message);
                            }

                            //
                            int eye2_WonLoss = myStackWonLoss_.Pop();
                            string WonLossString_ = String.Empty;
                            if (eye2_WonLoss == 0)
                            {
                                WonLossString_ = "L";
                            }
                            if (eye2_WonLoss == 1)
                            {
                                WonLossString_ = "W";
                            }  
                            string s20343_ = String.Format("OpponentID, Rating, W/L result (W=Win; L=Loss): {0},{1:0.0},{2} ", eye1_OpponentID, rating01temp_, WonLossString_);
                            COutputStrings.Add(s20343_);
                        }
                    }

                    string s3_3qaw_ = "...end chosen player data...";
                    COutputStrings.Add(s3_3qaw_);
                }
            }
        }
        
        List<ChessPlayer> chessPlayersCurrentList = new List<ChessPlayer>();
        public List<ChessPlayer> ChessPlayersCurrentList
        {
            get
            {
                return chessPlayersCurrentList;
            }
            private set
            {
                chessPlayersCurrentList = value;
            }

        }

        public void PrintChessPlayersDictionary()
        {
            foreach (KeyValuePair<int, ChessPlayer> KV in ChessPlayersDict)
            {               
                string S28awrwr_ = String.Format("Player ID: {0}, has rating: {1:0.0}", KV.Value.PlayerID, KV.Value.Rating);
                COutputStrings.Add(S28awrwr_);
            }
        }

        public void ChessCombatFunc()  //driver method determines which chessplayers will win per match and over many iterations
        {
            if (numberGamesPlayed <= 0 || numberIterations == 0) return; //something wrong
            int IttTotalNum = this.numberIterations; int NumGamesPlayedInt = this.numberGamesPlayed;
            if (subjectPlayerIdfound == -1) return; //means subject player not initialized, something wrong
            if (WinningChessPlayerLst == null) return; //something wrong
            this.ChessPlayerListSort(); //sort once at beginning
                        Console.WriteLine("Progress of program, percent done:");
 
                        int progressBarInt = 0; //for progress bar
                        int ProgressInt = 0; //should go from zero to ten
                        decimal DecimalDivider = (decimal)IttTotalNum / 10.0M;
                        DecimalDivider = Math.Round(DecimalDivider);  
                        progressBarInt = (int)DecimalDivider; //should be some whole number, and since iterations >= 10 won't have divide by zero problem
 
            for (int i = 0; i < IttTotalNum; i++)
            {
                for (int j = 0; j < NumGamesPlayedInt; j++)
                {
                    if (j == 0)
                    {
                        ChessPlayerListSortFirstRoundOnly(); //first round is special, and players play according to the routine of strongest plays weakest, second strongest plays second weakest...
                    }
                    else
                    {
                        ChessPlayerListSort();
                    }
                    this.ChessPlayersCombat(j); //--------------------important function

                } //end inner loop

                ////progress bar here  
                int modolo_ = i % progressBarInt;  //does not need divide by zero condition since #itt >= 10
                if (modolo_ == 0)
                {
                    Console.Write("{0}%...", ProgressInt);
                    ProgressInt = ProgressInt + 10;
                }

                ////now record winner for this round
                RecordWinnerFunc(i);    //--------------------important function             
            } //end outer loop

            this.ComputePercentages();
 
        }

        private void ComputePercentages()
        {
            if (subjectPlayerIdfound == -1) return;
            try
            {
                double PercentWins_ = this.ComputeSubjectPlayerPercentWinsForAllIterations();
                ChessPlayer cp_temp1 = ChessPlayersDict[subjectPlayerIdfound];
                string sblank02s1_ = String.Empty;
                COutputStrings.Add(sblank02s1_);

                Console.WriteLine();
                Console.WriteLine("Subject Player of Elo {0} won {1} times out of {2} iterations, a total of {3:0.0%} percent",
                    cp_temp1.Rating, subjectPlayerNumTotalWinsInt, numberIterations, PercentWins_);
                string S234210A_ = String.Format("Subject Player of Elo {0} won {1} times out of {2} iterations, a total of {3:0.0%} percent",
                    cp_temp1.Rating, subjectPlayerNumTotalWinsInt, numberIterations, PercentWins_);
                COutputStrings.Add(S234210A_);
                //now show what a close winning player won
                double PercentWinsWinnerCloseToChosenPlayer_ = this.ComputeWinnerThatIsCloseInEloToSubjectPlayerPercentWinsAllIterations();
                int eloUpperBound_ = cp_temp1.Rating + PlusMinusEloInt;
                int eloLowerBound_ = cp_temp1.Rating - PlusMinusEloInt;
                Console.WriteLine();
                Console.WriteLine("Winning Players within 50 Elo of Subject player ({0} to {1}) won {2} times out of {3} iterations, a total of {4:0.0%}",
                        eloLowerBound_, eloUpperBound_, winnerPlayerNumberTotalWinsPlusMinusEloInt, numberIterations, PercentWinsWinnerCloseToChosenPlayer_);
                string S4582342ab_ = String.Format("Winning Players within 50 Elo of Subject player ({0} to {1}) won {2} times out of {3} iterations, a total of {4:0.0%}",
                        eloLowerBound_, eloUpperBound_, winnerPlayerNumberTotalWinsPlusMinusEloInt, numberIterations, PercentWinsWinnerCloseToChosenPlayer_);
                COutputStrings.Add(S4582342ab_);
                
                //compute 'quadrants' of normal distribution to be used for stats
                int twoSigmaAboveMeanElo_ = (int)(Math.Round(MeanAllPlayers)) + (2 * (int)(Math.Round(StdDeviationAllPlayers)));
                int within1SigmaUpperElo_ = (int)(Math.Round(MeanAllPlayers)) + (1 * (int)(Math.Round(StdDeviationAllPlayers)));
                int within1SigmaLowerElo_ = (int)(Math.Round(MeanAllPlayers)) - (1 * (int)(Math.Round(StdDeviationAllPlayers)));
                int twoSigmaBelowMeanElo_ = (int)(Math.Round(MeanAllPlayers)) - (2 * (int)(Math.Round(StdDeviationAllPlayers)));
                //now show what the players in the three phases from the mean, standard deviation won
                //III. Greater than two sigma
                double PercentWinsWinnerGreaterThanTwoSigma_ = this.ComputeWinnerThatIsTwoSigmaGreaterPercentWinsAllIterations();


                Console.WriteLine();
                Console.WriteLine("Winning Players having an Elo:{0} or greater, two sigma or greater than the mean, won {1} times out of {2} iterations, a total of {3:0.0%}",
                    twoSigmaAboveMeanElo_, winnerPlayerTwoSigmaGreaterint, numberIterations, PercentWinsWinnerGreaterThanTwoSigma_);
                string S4783qs34_ = String.Format("Winning Players having an Elo:{0} or greater, two sigma or greater from the mean, won {1} times out of {2} iterations, a total of {3:0.0%}",
                    twoSigmaAboveMeanElo_, winnerPlayerTwoSigmaGreaterint, numberIterations, PercentWinsWinnerGreaterThanTwoSigma_);
                COutputStrings.Add(S4783qs34_);

                // IIB.  II.B II.5 between one and two sigma
                double PercentWinsWinnerBetweenOneAndTwoSigma_ = this.ComputerWinnerThatIsBetweenOneSigmaAndTwoSigmaPercentWinsAllIterations();

                Console.WriteLine();
                Console.WriteLine("Winning Players having an Elo between:{0} and {1}, 1-2 sigma above mean, won {2} times out of {3} iterations, a total of {4:0.0%}",
                    within1SigmaUpperElo_, twoSigmaAboveMeanElo_, winnerPlayerBetweenOneAndTwoSigmaGreaterInt, numberIterations, PercentWinsWinnerBetweenOneAndTwoSigma_);
                string s38q2ad3asd_ = String.Format("Winning Players having an Elo between:{0} and {1}, 1-2 sigma above mean, won {2} times out of {3} iterations, a total of {4:0.0%}",
                    within1SigmaUpperElo_, twoSigmaAboveMeanElo_, winnerPlayerBetweenOneAndTwoSigmaGreaterInt, numberIterations, PercentWinsWinnerBetweenOneAndTwoSigma_);
                COutputStrings.Add(s38q2ad3asd_);

                //II. between plus or minus one sigma from mean 
                double PercentWinsWinnerWithinOneSigmaOfMean_ = this.ComputeWinnerWithinOneSigmaPercentWinsAllIterations();

                Console.WriteLine();
                Console.WriteLine("Winning Players having an Elo of {0} to {1}, within 1 sigma of the mean:{2:0.0}, won {3} out of {4} iterations, a total of: {5:0.0%}",
                    within1SigmaLowerElo_, within1SigmaUpperElo_, MeanAllPlayers, winnerPlayerWithinOneSigmaint, numberIterations, PercentWinsWinnerWithinOneSigmaOfMean_);
                string s389123wut29z_ = String.Format("Winning Players having an Elo of {0} to {1}, within 1 sigma of the mean:{2:0.0}, won {3} out of {4} iterations, a total of: {5:0.0%}",
                    within1SigmaLowerElo_, within1SigmaUpperElo_, MeanAllPlayers, winnerPlayerWithinOneSigmaint, numberIterations, PercentWinsWinnerWithinOneSigmaOfMean_);
                COutputStrings.Add(s389123wut29z_);
                //below mean, between -2s >= x < -1s
                double PercentWins1to2SigmaBelowMean_ = this.ComputerWinnerBetweenOneAndTwoSigmaBELOWmeanPercentWinsAllItt();

                Console.WriteLine();
                Console.WriteLine("Winning Players having an Elo of {0} to {1}, between 1 to 2 sigmas below mean ({2}), won {3} out of {4} iterations, a total of: {5:0.0%}",
                    twoSigmaBelowMeanElo_, within1SigmaLowerElo_, MeanAllPlayers, winnerPlayerBetweenOneAndTwoSigmaLESSERInt, numberIterations, PercentWins1to2SigmaBelowMean_);
                string s38238wW_ = String.Format("Winning Players having an Elo of {0} to {1}, between 1 to 2 sigmas below mean ({2}), won {3} out of {4} iterations, a total of: {5:0.0%}",
                    twoSigmaBelowMeanElo_, within1SigmaLowerElo_, MeanAllPlayers, winnerPlayerBetweenOneAndTwoSigmaLESSERInt, numberIterations, PercentWins1to2SigmaBelowMean_);
                COutputStrings.Add(s38238wW_);

                // Below two sigma from mean -2s > x
                double PercentWinsBelowTwoSigmaFromMean_ = this.ComputeWinnerLessThanTwoSigmaBelowMeanPercentWinsAllIterations();

                Console.WriteLine();
                Console.WriteLine("Winning Players having an Elo below: {0}, below 2 sigma of mean, won {1} out of {2} iterations, a total of: {3:0.0%}",
                    twoSigmaBelowMeanElo_, winnerPlayerTwoSigmaLessint, numberIterations, PercentWinsBelowTwoSigmaFromMean_);
                string s48292swai49_ = String.Format("Winning Players having an Elo below: {0}, below 2 sigmas of mean, won {1} out of {2} iterations, a total of: {3:0.0%}",
                    twoSigmaBelowMeanElo_, winnerPlayerTwoSigmaLessint, numberIterations, PercentWinsBelowTwoSigmaFromMean_);
                COutputStrings.Add(s48292swai49_);

                COutputStrings.Add(".................................");
                    

            }
            catch (KeyNotFoundException ex)
            {
                Console.WriteLine(ex.Message);
            }
            catch (Exception ex1)
            {
                Console.WriteLine(ex1.Message);
            } 
        }

        private double ComputeSubjectPlayerPercentWinsForAllIterations()
        {
            double percentSubjectPlayerWon_ = 0.0;
            if (subjectPlayerNumTotalWinsInt != 0 && numberIterations != 0)
            {
                subjectPlayerPercentWin = (double)subjectPlayerNumTotalWinsInt / (double)numberIterations;
                percentSubjectPlayerWon_ = subjectPlayerPercentWin;
            }

            return percentSubjectPlayerWon_; 
        }

        private double ComputeWinnerThatIsCloseInEloToSubjectPlayerPercentWinsAllIterations()
        {
            double percentWinningPlayerCloseToWon_ = 0.0; // 
            if (winnerPlayerNumberTotalWinsPlusMinusEloInt != 0 && numberIterations != 0)
            {
                percentWinningPlayerCloseToWon_ = (double)winnerPlayerNumberTotalWinsPlusMinusEloInt / (double)numberIterations;                
            } 

            return percentWinningPlayerCloseToWon_;
        }

        private double ComputeWinnerThatIsTwoSigmaGreaterPercentWinsAllIterations()
        {
            double percentWinningTwoSigmaGreater_ = 0.0;
            if (winnerPlayerTwoSigmaGreaterint != 0 && numberIterations != 0)
            {
                percentWinningTwoSigmaGreater_ = (double)winnerPlayerTwoSigmaGreaterint / (double)numberIterations;              
            }

            return percentWinningTwoSigmaGreater_;
        }

        private double ComputerWinnerThatIsBetweenOneSigmaAndTwoSigmaPercentWinsAllIterations()
        {
            double percentWinningBetweenOneAndTwoSigmaGreater_ = 0.0;
            if (winnerPlayerBetweenOneAndTwoSigmaGreaterInt != 0 && numberIterations != 0)
            {
                percentWinningBetweenOneAndTwoSigmaGreater_ = (double)winnerPlayerBetweenOneAndTwoSigmaGreaterInt / (double)numberIterations;
            }
            return percentWinningBetweenOneAndTwoSigmaGreater_;
        }

        private double ComputeWinnerWithinOneSigmaPercentWinsAllIterations()
        {
            double percentWinningWithinOneSigma_ = 0.0;
            if (winnerPlayerWithinOneSigmaint != 0 && numberIterations != 0)
            {
                percentWinningWithinOneSigma_  = (double)winnerPlayerWithinOneSigmaint / (double)numberIterations;               
            }  

            return percentWinningWithinOneSigma_;
        }

        private double ComputerWinnerBetweenOneAndTwoSigmaBELOWmeanPercentWinsAllItt()
        {
            double percentWinsLessthanMeanBetweenOneAndTwoSigma_ = 0.0;
            if (winnerPlayerBetweenOneAndTwoSigmaLESSERInt != 0 && numberIterations != 0)
            {
                percentWinsLessthanMeanBetweenOneAndTwoSigma_ = (double)winnerPlayerBetweenOneAndTwoSigmaLESSERInt / (double) numberIterations;
            }
            return percentWinsLessthanMeanBetweenOneAndTwoSigma_;
        }

        private double ComputeWinnerLessThanTwoSigmaBelowMeanPercentWinsAllIterations()
        {
            double percentWinningLessThanTwoSigmaBelowMean_ = 0.0;
            if (winnerPlayerTwoSigmaLessint != 0 && numberIterations != 0)
            {
                percentWinningLessThanTwoSigmaBelowMean_ = (double)winnerPlayerTwoSigmaLessint / (double)numberIterations;
            }
            return percentWinningLessThanTwoSigmaBelowMean_;
        }


        private void ChessPlayerListSortFirstRoundOnly()
        {
            int length01_ = chessPlayersCurrentList.Count;
            int ModuloResult = length01_ % 2;
            if (ModuloResult != 0) return; //means list not an even number, something wrong, return;
            int HalfLength = length01_ / 2;
            Stack<ChessPlayer> TopHalfChessPlayers = new Stack<ChessPlayer>();
            Stack<ChessPlayer> BottomHalfChessPlayers = new Stack<ChessPlayer>();
            for (int i = 0; i < HalfLength; i++)
            {
                TopHalfChessPlayers.Push(chessPlayersCurrentList[i]);
            }
            for (int j = (length01_ - 1); j >= HalfLength; j--) // 
            {
                BottomHalfChessPlayers.Push(chessPlayersCurrentList[j]);
            }
            //now arrange so top and bottom meet so index 0
            //first clear current list
            chessPlayersCurrentList = new List<ChessPlayer>();

            for (int k = 0; k < HalfLength; k++)
            {
                ChessPlayer cp1 = TopHalfChessPlayers.Pop();
                ChessPlayer cp2 = BottomHalfChessPlayers.Pop();
                chessPlayersCurrentList.Add(cp1);
                chessPlayersCurrentList.Add(cp2);                 
            }

        }

        private void RecordWinnerFunc(int itterationRoundNumber)
        {
            // sort the current list (no need to update OpponentScoreInt since already done)

            IEnumerable<ChessPlayer> result1 = new List<ChessPlayer>();

            result1 = chessPlayersCurrentList.Select(q => q).OrderByDescending(q => q.TotalScore)
                        .ThenByDescending(q => q.OpponentScoreInt)
                        .ThenByDescending(q => q.Rating);

            chessPlayersCurrentList = result1.ToList();

            //get top candidates in chessPlayersCurrentList list, if they exist, and place in WinningChessPlayerLst 
             
            if (chessPlayersCurrentList[0] != null)
            {
                ChessPlayer cp = chessPlayersCurrentList[0];     
               
                                    if (cp.Rating <= subjectPlayerEloUpperBound && cp.Rating >= subjectPlayerEloLowerBound)
                                    {
                                        winnerPlayerNumberTotalWinsPlusMinusEloInt = winnerPlayerNumberTotalWinsPlusMinusEloInt + 1; //increment winning player that's within 50 elo points of the chosen player
                                    }
                //five phases of scalar distribution:  I> two sigma or greater; II: within 1 sig; II.5 1s < x < 2s  III: less than two sigma or less IIIB: -2s < x < -1s

                            if (cp.Rating >= twoSigmaAboveMeanElo)
                            {
                                winnerPlayerTwoSigmaGreaterint++;                                
                            }

                            if (cp.Rating >= within1SigmaUpperElo && cp.Rating < twoSigmaAboveMeanElo)
                            {
                                winnerPlayerBetweenOneAndTwoSigmaGreaterInt++;
                            }                             

                            if (cp.Rating >= within1SigmaLowerElo && cp.Rating < within1SigmaUpperElo)
                            {
                                winnerPlayerWithinOneSigmaint++;
                            }

                            // III.B between -2s and -1s from the mean (lower side)
                            if (cp.Rating >= twoSigmaLessThanMeanElo && cp.Rating < within1SigmaLowerElo)
                            {
                                winnerPlayerBetweenOneAndTwoSigmaLESSERInt++;
                            }
                
                        //I> two sigma or less than  
                            if (cp.Rating < twoSigmaLessThanMeanElo)
                        {
                            winnerPlayerTwoSigmaLessint++;
                        }
               
                //
                if (cp.PlayerID == subjectPlayerIdfound) //increment only for subject ID  
                {
                    subjectPlayerNumTotalWinsInt = subjectPlayerNumTotalWinsInt + 1; //increment total wins
                }

                        // calculate winningchessplayer extraordinary upsets
                        if (WinningChessPlayerExtraordinaryUpsetsLst.Count < 10) //top ten upsets recorded only in list
                        {
                            // record extraordinary upsets here
                            //calculate any extraordinary upsets as follows:
                            // (1) a win by a ChessPlayer having elo < 1.5 sigma from the mean (below mean), and Number Players >= 10 (to give good Gaussian spread)

                            //make it 2 sigma not 1.5 since rounding error produces uncertainty
                            if (cp.Rating < twoSigmaLessThanMeanElo && numberOfChessPlayers >= 10) //you must have at least 10 players to record top ten upsets.  This 10 number of players is arbitrary but prevents very small tournaments from being considered an upset.
                            {
                                WinningChessPlayer winningCP = this.ComputeAvgOppEloAndPerfElo(cp);
                                winningCP.RoundN = itterationRoundNumber;
                                WinningChessPlayerExtraordinaryUpsetsLst.Add(winningCP); 
                            }
                        }               

                if (isVerbose == true) //only record if verbose mode set (useful for testing/debug)
                {                    
                     if (WinningChessPlayerLst.Count < 1000) //record just first one thousand //(cp.PlayerID == subjectPlayerIdfound) //record Lists only for subject ID (otherwise tedious)
                    {
                        WinningChessPlayer winningCP_ = this.ComputeAvgOppEloAndPerfElo(cp);
                        winningCP_.RoundN = itterationRoundNumber;                        
                        WinningChessPlayerLst.Add(winningCP_);  
                    }
                } //end of 'if isVerbose' condition
            }
            else
            {
                ChessPlayer cp = new ChessPlayer(); //some sort of error  
                WinningChessPlayer WinningCP = new WinningChessPlayer(cp);
                WinningChessPlayerLst.Add(WinningCP);
            }

            ////now zero out the chessPlayerCurrentList so to reuse in next iteration 
            
            foreach (ChessPlayer cp in chessPlayersCurrentList)
            {
                cp.ZeroOutAllZeroableParametersFunction();
            }

            //now must re-sort or else  you'll get last rounds (possibly weaker) winner at top
            IEnumerable<ChessPlayer> result2 = new List<ChessPlayer>();

            result2 = chessPlayersCurrentList.Select(q => q).OrderByDescending(q => q.TotalScore)
                        .ThenByDescending(q => q.OpponentScoreInt)
                        .ThenByDescending(q => q.Rating);

            chessPlayersCurrentList = result2.ToList();

        }

        private WinningChessPlayer ComputeAvgOppEloAndPerfElo(ChessPlayer cp)
        {
            WinningChessPlayer winningCP_ = new WinningChessPlayer(cp);
             winningCP_.PlayerOpponentIDList = cp.PlayerOpponentIDList;
                        winningCP_.WonLossList = cp.WonLossList;

                        //now go through and compute average opponent Elo faced 
                         // this routine to compute average ELO opponent and performance of winner
                        double AvgRatingOpp_ = 0.0;
                        double AvgRating_NumeratorD_ = 0.0;
                        double AverRating_DenominatorD_ = (double)winningCP_.PlayerOpponentIDList.Count;

                        foreach (int iPO in winningCP_.PlayerOpponentIDList)
                        {
                            try
                            {
                                ChessPlayer cp_temp = ChessPlayersDict[iPO]; //fastest way of accessing a dictionary if key is certain to be found
                                AvgRating_NumeratorD_ = AvgRating_NumeratorD_ + cp_temp.Rating;
                            }
                            catch (KeyNotFoundException ex)
                            {
                                Console.WriteLine(ex.Message);
                                 
                            }
                            catch (Exception ex1)
                            {
                                Console.WriteLine(ex1.Message);
                            }

                            if (AverRating_DenominatorD_ != 0)
                            {
                                AvgRatingOpp_ = AvgRating_NumeratorD_ / AverRating_DenominatorD_;
                            }
                            else
                            {
                                AvgRatingOpp_ = -1.0d;
                            }
                        }
                        winningCP_.OppositionRatingAvg = AvgRatingOpp_;
                        //  now figure out what the performance Elo was
                        int N_totalNumberGamesPlayedInItt_ = numberGamesPlayed; //forms denominator of performance Elo
                        int Pts_scoredTotal_ = winningCP_.TotalScore;
                        double PercentWonD_ = (double)Pts_scoredTotal_ / (double)numberGamesPlayed;
                        //look up what the Elo was for this percentage

                        if (PercentWonD_ <= 0.50 || PercentWonD_ > 1.0)  //first check that less than 50% (otherwise makes no sense to have won a tournament with less than 50%) //sanity check for >1
                        {
                            winningCP_.PerformanceRatingElo = 0.0;
                        }
                        else
                        {
                            //means the loser, on average, had an Elo less than the winner.  
                            //hence winning Elo = AvgRatingOpp_ + Diff.Elo Lookup Table 
                            double PercentLostByOpposition = 1.0 - PercentWonD_;
                            int LoserEloDifference = ReverseLookupRatingsTable(PercentLostByOpposition);

                            if (AvgRatingOpp_ != 0.0 || AvgRatingOpp_ != -1) //sanity check
                            {
                                winningCP_.PerformanceRatingElo = AvgRatingOpp_ + LoserEloDifference;
                            }
                            else
                            {
                                winningCP_.PerformanceRatingElo = 0.0;
                            }
                        }

            return winningCP_;
        }

        Dictionary<int, ChessPlayer> ChessPlayersDict = new Dictionary<int, ChessPlayer>();

        private void ChessPlayersCombat(int RoundNumber)  //determines which players will win in any round (of iterations)
        {
            //split the currentlist into two equal lists of chessplayers
            int LengthL1 = chessPlayersCurrentList.Count;
            List<ChessPlayer> chessPlayerOdd_ = new List<ChessPlayer>();
            List<ChessPlayer> chessPlayerEven_ = new List<ChessPlayer>();
            for (int i = 0; i < LengthL1; i++)
            {
                int ModuloResult = i % 2;
                if (ModuloResult == 0)
                {
                    chessPlayerEven_.Add(chessPlayersCurrentList[i]);
                }
                else
                {
                    chessPlayerOdd_.Add(chessPlayersCurrentList[i]);
                }
            }


            int LengthL2 = chessPlayerOdd_.Count;

          //  Random rand = new Random(); //time dependent seed //! don't put here!!  it will reset too fast! 
            for (int j = 0; j < LengthL2; j++) //do a round of contests
            {
                ChessPlayer cpStronger = new ChessPlayer();
                ChessPlayer cpWeaker = new ChessPlayer();
                cpStronger = chessPlayerOdd_[j];
                cpWeaker = chessPlayerEven_[j];
                if (cpStronger.Rating <= cpWeaker.Rating)
                {
                    ChessPlayer cpTemp_ = new ChessPlayer();
                    cpTemp_ = cpStronger;
                    cpStronger = cpWeaker;
                    cpWeaker = cpTemp_;
                }

                double ratingDifferenceD = (cpStronger.Rating - cpWeaker.Rating);
                int ratingDifferenceInt = (int)(ratingDifferenceD);
                
                double underDogVictoryProbPercent_ = LookupRatingsTable(ratingDifferenceInt);
                int underDogVictoryProbInt_ = (int)(1000.00 * underDogVictoryProbPercent_);
                int iRand = rand.Next(0, 1000); //0 to 1000 inclusive  

                if (iRand <= underDogVictoryProbInt_)
                {
                    cpWeaker.TotalScore = cpWeaker.TotalScore + 1;
                    cpStronger.WonLossOpponentIDLog(0, cpWeaker.PlayerID); //lost to the weaker player
                    cpWeaker.WonLossOpponentIDLog(1, cpStronger.PlayerID); //beat the stronger player
                }
                else //means underdog lost
                {
                    cpStronger.TotalScore = cpStronger.TotalScore + 1;
                    cpStronger.WonLossOpponentIDLog(1, cpWeaker.PlayerID);
                    cpWeaker.WonLossOpponentIDLog(0, cpStronger.PlayerID);
                }
                              
            }

        }

        private double LookupRatingsTable(int RD)
        {
            double rP = 0.0;

            if (RD > 999) { rP = 0.0; return rP; }
            if (RD <= 999 && RD > 735) { rP = 0.01; return rP; }
            if (RD <= 735 && RD > 619) { rP = 0.02; return rP; }
            if (RD <= 619 && RD > 559) { rP = 0.03; return rP; }
            if (RD <= 559 && RD > 517) { rP = 0.04; return rP; }
            if (RD <= 517 && RD > 484) { rP = 0.05; return rP; }
            if (RD <= 484 && RD > 456) { rP = 0.06; return rP; }
            if (RD <= 456 && RD > 432) { rP = 0.07; return rP; }
            if (RD <= 432 && RD > 411) { rP = 0.08; return rP; }
            if (RD <= 411 && RD > 391) { rP = 0.09; return rP; }
            if (RD <= 391 && RD > 374) { rP = 0.10; return rP; }
            if (RD <= 374 && RD > 357) { rP = 0.11; return rP; }
            if (RD <= 357 && RD > 344) { rP = 0.12; return rP; }
            if (RD <= 344 && RD > 328) { rP = 0.13; return rP; }
            if (RD <= 328 && RD > 315) { rP = 0.14; return rP; }
            if (RD <= 315 && RD > 302) { rP = 0.15; return rP; }
            if (RD <= 302 && RD > 290) { rP = 0.16; return rP; }
            if (RD <= 290 && RD > 278) { rP = 0.17; return rP; }
            if (RD <= 278 && RD > 267) { rP = 0.18; return rP; }
            if (RD <= 267 && RD > 256) { rP = 0.19; return rP; }
            if (RD <= 256 && RD > 245) { rP = 0.20; return rP; }
            if (RD <= 245 && RD > 235) { rP = 0.21; return rP; }
            if (RD <= 235 && RD > 225) { rP = 0.22; return rP; }
            if (RD <= 225 && RD > 215) { rP = 0.23; return rP; }
            if (RD <= 215 && RD > 206) { rP = 0.24; return rP; }
            if (RD <= 206 && RD > 197) { rP = 0.25; return rP; }
            if (RD <= 197 && RD > 188) { rP = 0.26; return rP; }
            if (RD <= 188 && RD > 179) { rP = 0.27; return rP; }
            if (RD <= 179 && RD > 170) { rP = 0.28; return rP; }
            if (RD <= 170 && RD > 162) { rP = 0.29; return rP; }
            if (RD <= 162 && RD > 153) { rP = 0.30; return rP; }
            if (RD <= 153 && RD > 145) { rP = 0.31; return rP; }
            if (RD <= 145 && RD > 137) { rP = 0.32; return rP; }
            if (RD <= 137 && RD > 129) { rP = 0.33; return rP; }
            if (RD <= 129 && RD > 121) { rP = 0.34; return rP; }
            if (RD <= 121 && RD > 113) { rP = 0.35; return rP; }
            if (RD <= 113 && RD > 106) { rP = 0.36; return rP; }
            if (RD <= 106 && RD > 98) { rP = 0.37; return rP; }
            if (RD <= 98 && RD > 91) { rP = 0.38; return rP; }
            if (RD <= 91 && RD > 83) { rP = 0.39; return rP; }
            if (RD <= 83 && RD > 76) { rP = 0.40; return rP; }
            if (RD <= 76 && RD > 68) { rP = 0.41; return rP; }
            if (RD <= 68 && RD > 61) { rP = 0.42; return rP; }
            if (RD <= 61 && RD > 53) { rP = 0.43; return rP; }
            if (RD <= 53 && RD > 46) { rP = 0.44; return rP; }
            if (RD <= 46 && RD > 39) { rP = 0.45; return rP; }
            if (RD <= 39 && RD > 32) { rP = 0.46; return rP; }
            if (RD <= 32 && RD > 25) { rP = 0.47; return rP; }
            if (RD <= 25 && RD > 17) { rP = 0.48; return rP; }
            if (RD <= 17 && RD > 10) { rP = 0.49; return rP; }
            if (RD <= 10 && RD >= 0) { rP = 0.50; return rP; }
 
            return rP;


        }

        private int ReverseLookupRatingsTable(double pW) //pW = percentWin
        {
            int rd = 0; //rd = Rating difference in Elo
            if (pW < 0.01) { rd = 5555; return rd; }
            if (pW >= 0.01 && pW < 0.02) { rd = 677; return rd; }
            if (pW >= 0.02 && pW < 0.03) { rd = 589; return rd; }
            if (pW >= 0.03 && pW < 0.04) { rd = 538; return rd; }
            if (pW >= 0.04 && pW < 0.05) { rd = 501; return rd; }
            if (pW >= 0.05 && pW < 0.06) { rd = 470; return rd; }
            if (pW >= 0.06 && pW < 0.07) { rd = 444; return rd; }
            if (pW >= 0.07 && pW < 0.08) { rd = 422; return rd; }
            if (pW >= 0.08 && pW < 0.09) { rd = 401; return rd; }
            if (pW >= 0.09 && pW < 0.10) { rd = 383; return rd; }
            if (pW >= 0.10 && pW < 0.11) { rd = 366; return rd; }
            if (pW >= 0.11 && pW < 0.12) { rd = 351; return rd; }
            if (pW >= 0.12 && pW < 0.13) { rd = 336; return rd; }
            if (pW >= 0.13 && pW < 0.14) { rd = 322; return rd; }
            if (pW >= 0.14 && pW < 0.15) { rd = 309; return rd; }
            if (pW >= 0.15 && pW < 0.16) { rd = 296; return rd; }
            if (pW >= 0.16 && pW < 0.17) { rd = 284; return rd; }
            if (pW >= 0.17 && pW < 0.18) { rd = 273; return rd; }
            if (pW >= 0.18 && pW < 0.19) { rd = 262; return rd; }
            if (pW >= 0.19 && pW < 0.20) { rd = 251; return rd; }
            if (pW >= 0.20 && pW < 0.21) { rd = 240; return rd; }
            if (pW >= 0.21 && pW < 0.22) { rd = 230; return rd; }
            if (pW >= 0.22 && pW < 0.23) { rd = 220; return rd; }
            if (pW >= 0.23 && pW < 0.24) { rd = 211; return rd; }
            if (pW >= 0.24 && pW < 0.25) { rd = 202; return rd; }
            if (pW >= 0.25 && pW < 0.26) { rd = 193; return rd; }
            if (pW >= 0.26 && pW < 0.27) { rd = 184; return rd; }
            if (pW >= 0.27 && pW < 0.28) { rd = 175; return rd; }
            if (pW >= 0.28 && pW < 0.29) { rd = 166; return rd; }
            if (pW >= 0.29 && pW < 0.30) { rd = 158; return rd; }
            if (pW >= 0.30 && pW < 0.31) { rd = 149; return rd; }
            if (pW >= 0.31 && pW < 0.32) { rd = 141; return rd; }
            if (pW >= 0.32 && pW < 0.33) { rd = 133; return rd; }
            if (pW >= 0.33 && pW < 0.34) { rd = 125; return rd; }
            if (pW >= 0.34 && pW < 0.35) { rd = 117; return rd; }
            if (pW >= 0.35 && pW < 0.36) { rd = 110; return rd; }
            if (pW >= 0.36 && pW < 0.37) { rd = 102; return rd; }
            if (pW >= 0.37 && pW < 0.38) { rd = 95; return rd; }
            if (pW >= 0.38 && pW < 0.39) { rd = 87; return rd; }
            if (pW >= 0.39 && pW < 0.40) { rd = 80; return rd; }
            if (pW >= 0.40 && pW < 0.41) { rd = 72; return rd; }
            if (pW >= 0.41 && pW < 0.42) { rd = 65; return rd; }
            if (pW >= 0.42 && pW < 0.43) { rd = 57; return rd; }
            if (pW >= 0.43 && pW < 0.44) { rd = 50; return rd; }
            if (pW >= 0.44 && pW < 0.45) { rd = 43; return rd; }
            if (pW >= 0.45 && pW < 0.46) { rd = 36; return rd; }
            if (pW >= 0.46 && pW < 0.47) { rd = 29; return rd; }
            if (pW >= 0.47 && pW < 0.48) { rd = 21; return rd; }
            if (pW >= 0.48 && pW < 0.49) { rd = 14; return rd; }
            if (pW >= 0.49 && pW <= 0.50) { rd = 5; return rd; }
            
            return 0;
        }

        private void ChessPlayerListSort()
        {
          //  if (chessPlayersCurrentList == null) return; //not really necessary 
            this.SetChessPlayerOpponentScoreInt(); //update all the OpponentsScoreInt fields
            IEnumerable<ChessPlayer> result1 = new List<ChessPlayer>();

            result1 = chessPlayersCurrentList.Select(q => q).OrderByDescending(q => q.TotalScore)
                        .ThenByDescending(q => q.OpponentScoreInt)
                        .ThenByDescending(q => q.Rating);

            chessPlayersCurrentList = result1.ToList();

        }
        
        private void SetChessPlayerOpponentScoreInt()  //this method not used outside of class ChessDestiny so OK to set private
        {
            int OpponenentScoreCummInt;
            foreach (ChessPlayer cp in chessPlayersCurrentList)
            {
                OpponenentScoreCummInt = 0;
                foreach (int iPO in cp.PlayerOpponentIDList)
                {
                    try
                    {
                       
                        ChessPlayer cp_temp = ChessPlayersDict[iPO]; //fastest way of accessing a dictionary if key is certain to be found
                        
                        OpponenentScoreCummInt = cp_temp.TotalScore + OpponenentScoreCummInt; //note of course the TotalScore is of interest here, for each opponent
                    }
                    catch (KeyNotFoundException ex)
                    {
                        Console.WriteLine("key not found in SetPlayerOpponentScoreInt:{0}", ex.Message);
                    }
                    catch (Exception ex1)
                    {
                        Console.WriteLine(ex1.Message);
                    }
                }
                cp.OpponentScoreInt = OpponenentScoreCummInt;
            }
             
        }

        public List<string> COutputStrings = new List<string>();  //stores the strings to be written in the text file output

        public void CreateTextFile() //creates the text file output
        {
            if (COutputStrings.Count == 0)
            {
                Console.WriteLine("Nothing to print to text");
                return;
            }

            try
            {
                using (TextWriter tw = File.CreateText("SCTWPS.txt"))
                {
                    DateTime dtCurrentTime = DateTime.Now;
                    tw.WriteLine("Log, file created at time:{0}", dtCurrentTime);
                    tw.WriteLine("---");
                    tw.WriteLine();

                    foreach (string s in COutputStrings)
                    {
                        tw.WriteLine(s);

                    }
                    tw.WriteLine();
                    tw.WriteLine("---");
                }

            }
            catch (System.UnauthorizedAccessException ex0)
            {
                Console.WriteLine(ex0.Message);
            }
            catch (System.NotSupportedException ex1)
            {
                Console.WriteLine(ex1.Message);
            }
            catch (Exception ex2)
            {
                Console.WriteLine(ex2.Message);
            }
        }
             

    }
}

